package com.senlingspace.payment.core;

import java.math.BigDecimal;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.NumberUtil;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.github.rholder.retry.*;
import com.google.common.base.Strings;
import com.senlingspace.common.constant.HttpStatus;
import com.senlingspace.common.core.dingtalk.DingTalkService;
import com.senlingspace.common.core.domain.AjaxResult;
import com.senlingspace.common.core.redis.RedisCache;
import com.senlingspace.common.enums.*;
import com.senlingspace.common.exception.ServiceException;
import com.senlingspace.common.exception.payment.LakalaException;
import com.senlingspace.common.request.PaymentRequest;
import com.senlingspace.common.request.PrepaymentRequest;
import com.senlingspace.common.utils.*;
import com.senlingspace.framework.config.properties.WeChatProperties;
import com.senlingspace.payment.event.OrderAction;
import com.senlingspace.payment.lakala.bean.request.LakalaMicroPayRequest;
import com.senlingspace.payment.lakala.bean.request.LakalaPreorderRequest;
import com.senlingspace.payment.lakala.bean.response.LakalaMicroPayResponse;
import com.senlingspace.payment.lakala.bean.response.LakalaPreorderResponse;
import com.senlingspace.payment.lakala.bean.response.TradeQueryResponse;
import com.senlingspace.payment.lakala.service.LakalaMicroPayService;
import com.senlingspace.payment.lakala.service.LakalaPreorderService;
import com.senlingspace.system.domain.*;
import com.senlingspace.system.domain.dto.AreaDTO;
import com.senlingspace.system.domain.dto.CustomerAddressDTO;
import com.senlingspace.system.domain.vo.ReceiptInfoVo;
import com.senlingspace.system.domain.vo.SharesInvestorVo;
import com.senlingspace.system.domain.vo.SharesPosVo;
import com.senlingspace.system.domain.vo.ShopOperateVo;
import com.senlingspace.system.event.ActionEvent;
import com.senlingspace.system.mapper.*;
import com.senlingspace.system.service.*;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * 具体订单处理
 *
 * @author lebronjames
 * @date 2024/07/31
 */
@Slf4j
@Service
@AllArgsConstructor
public class ConcreteOrderProcess extends AbstractOrderProcessTemplate {

    private static final String INCR_ORDER_NUMBER_PREFIX = "incr_order_number:";

    private final Environment env;

    private final ProjectMapper projectMapper;
    private final SlkjShopMapper slkjShopMapper;
    private final SlkjTicketCategoryMapper slkjTicketCategoryMapper;
    private final SlkjFareSchemeDetailMapper slkjFareSchemeDetailMapper;
    private final SlkjOrderPricingSnapshotMapper slkjOrderPricingSnapshotMapper;
    private final SlkjProductMapper slkjProductMapper;
    private final SlkjOrderMapper slkjOrderMapper;
    private final SlkjOrderStatusLogMapper slkjOrderStatusLogMapper;
    private final SlkjTicketLevelMapper slkjTicketLevelMapper;
    private final SlkjFareSchemeMapper slkjFareSchemeMapper;
    private final SlkjOrderStatusCompensationMapper slkjOrderStatusCompensationMapper;
    private final LakalaMicroPayService lakalaMicroPayService;
    private final SlkjOrderLakalMapper slkjOrderLakalMapper;
    private final SlkjOrderSplitSnapshotMapper slkjOrderSplitSnapshotMapper;
    private final ISlkjShopService slkjShopService;
    private final SlkjFareSchemeShopMapper slkjFareSchemeShopMapper;
    private final SlkjShopPosMapper slkjShopPosMapper;
    private final SlkjShopInvestorMapper slkjShopInvestorMapper;
    private final SlkjShopProjectMapper slkjShopProjectMapper;
    private final SlkjShopOperateMapper slkjShopOperateMapper;
    private final RedisCache redisCache;
    private final DingTalkService dingTalkService;
    private final ISlkjOrderService iSlkjOrderService;
    private final SlkjCustomerMapper slkjCustomerMapper;
    private final LakalaPreorderService lakalaPreorderService;
    private final SlkjShopProductMapper slkjShopProductMapper;

    private final ApplicationEventPublisher applicationEventPublisher;

    private final WeChatProperties weChatProperties;
    private final SlkjCustomerAddressMapper slkjCustomerAddressMapper;
    private final SysAreaMapper sysAreaMapper;



    @SuppressWarnings("unchecked")
    @Override
    protected void validateRequest(PaymentRequest request, OrderSource source) throws ServiceException {
        log.info("参数验证...");
        Project project = projectMapper.selectProjectByProjectId(request.getProjectId());
        if (Objects.isNull(project)) {
            throw new ServiceException("项目不存在！");
        }

        SlkjShopProject currentShopProject = slkjShopProjectMapper.selectCurrentShowingProjectByShopId(request.getShopId());
        if (currentShopProject == null) {
            throw new ServiceException("当前门店无正在上映的项目！");
        }
        if (!currentShopProject.getProjectId().equals(request.getProjectId())) {
            throw new ServiceException("当前门店上映的项目已更新！");
        }

        SlkjShop shop = slkjShopMapper.selectSlkjShopByShopId(request.getShopId());
        if (Objects.isNull(shop)) {
            throw new ServiceException("门店不存在！");
        }

        if ("1".equals(shop.getStatus())) {
            throw new ServiceException("门店状态异常，禁止下单！");
        }

        if ("1".equals(shop.getDelFlag())) {
            throw new ServiceException("门店状态异常，禁止下单！");
        }

        AjaxResult check = slkjShopService.storeListingInformationCheck(shop.getShopId());
        HashMap<String, Boolean> data = (HashMap<String, Boolean>) check.get("data");
        if (!data.get("Projec")) {
            log.error("门店未关联项目！");
            throw new ServiceException("项目设置有误，请联系管理员！");
        }
        if (!data.get("Investor")) {
            log.error("门店未关联投资人！");
            throw new ServiceException("项目设置有误，请联系管理员！");
        }
        if (!data.get("IndependentAccount")) {
            log.error("门店未设置分账！");
            throw new ServiceException("项目设置有误，请联系管理员！");
        }

        SharesPosVo posVo = slkjShopPosMapper.selectPosShopByShopId(request.getShopId());
        if (Objects.isNull(posVo)) {
            log.error("票务系统未设置分账比例！");
            throw new ServiceException("项目设置有误，请联系管理员！");
        }

        List<Long> fareSchemeDetailIds = request.getPayInventories().stream()
                .filter(i -> i.getType().equals(PaymentRequest.TICKET))
                .map(PaymentRequest.PayInventory::getItemId)
                .collect(Collectors.toList());
        log.info("当前订单包含的门票（fare_scheme_detail_id）：{}", fareSchemeDetailIds);
        if (fareSchemeDetailIds.isEmpty()) {
            log.info("当前订单不包含门票！");
        } else {
            log.info("验证票价票类具体参数...");
            List<SlkjFareSchemeDetail> schemeDetails = slkjFareSchemeDetailMapper.selectSlkjFareSchemeDetailByIds(fareSchemeDetailIds);
            if (schemeDetails.size() != fareSchemeDetailIds.size()) {
                log.error("票价方案明细 [{}] 数据异常！", schemeDetails);
                throw new ServiceException("项目设置有误，请联系管理员！");
            }

            SlkjFareSchemeShop schemeShop = new SlkjFareSchemeShop();
            schemeShop.setShopId(request.getShopId());
            schemeShop.setFareSchemeId(schemeDetails.get(0).getFareSchemeId());
            schemeShop.setStatus(0);
            List<SlkjFareSchemeShop> fareSchemeShops = slkjFareSchemeShopMapper.selectSlkjFareSchemeShopList(schemeShop);
            if (CollectionUtils.isEmpty(fareSchemeShops)) {
                log.error("当前门店没有关联票价方案！");
                throw new ServiceException("项目设置有误，请联系管理员！");
            }

            List<Long> categoryIds = new ArrayList<>();
            for (SlkjFareSchemeDetail slkjFareSchemeDetail : schemeDetails) {
                if (slkjFareSchemeDetail.getChecked() == 0) {
                    log.error("票价方案发生变更：[slkj_fare_scheme_detail#id={}] 被弃用！", slkjFareSchemeDetail.getId());
                    throw new ServiceException("当前票价方案与最新方案存在误差，请刷新项目，重新下单！");
                }
                if (source.equals(OrderSource.SHOP) && "#".equals(slkjFareSchemeDetail.getShopPrice())) {
                    log.error("票价方案发生变更：[slkj_fare_scheme_detail#id={}] 禁止在门店售卖！", slkjFareSchemeDetail.getId());
                    throw new ServiceException("当前票价方案与最新方案存在误差，请刷新项目，重新下单！");
                } else if (source.equals(OrderSource.MINI_PROGRAM) && "#".equals(slkjFareSchemeDetail.getMiniProgramPrice())) {
                    log.error("票价方案发生变更：[slkj_fare_scheme_detail#id={}] 禁止在小程序售卖！", slkjFareSchemeDetail.getId());
                    throw new ServiceException("当前票价方案与最新方案存在误差，请刷新项目，重新下单！");
                }
//                目前抖音订单在录入本系统时，表示客户已经在抖音下单，无法禁止下单
//                else if (source.equals(OrderSource.DOUYIN) && "#".equals(slkjFareSchemeDetail.getDouyinPrice())) {
//                    log.error("票价方案发生变更：[slkj_fare_scheme_detail#id={}] 禁止在抖音售卖！", slkjFareSchemeDetail.getId());
//                    throw new ServiceException("当前票价方案与最新方案存在误差，请刷新项目，重新下单！");
//                }
                categoryIds.add(slkjFareSchemeDetail.getTicketCategoryId());
            }

            List<SlkjTicketCategory> ticketCategories = slkjTicketCategoryMapper.selectSlkjTicketCategoryByIds(categoryIds);
            if (ticketCategories.size() != categoryIds.size()) {
                log.error("票价方案明细中包含票类ID有误！");
                throw new ServiceException("票价方案明细中包含票类ID有误！");
            }
            log.info("票价票类参数，验证通过！");
        }

        List<Long> goodsIds = request.getPayInventories().stream()
                .filter(i -> i.getType().equals(PaymentRequest.GOODS))
                .map(PaymentRequest.PayInventory::getItemId)
                .collect(Collectors.toList());
        log.info("当前订单包含的商品（goods_id）：{}", goodsIds);
        if (goodsIds.isEmpty()) {
            log.info("当前订单不包含商品！");
        } else {
            log.info("验证商品具体参数...");
            List<SlkjProduct> products = slkjProductMapper.selectProductByProductIds(goodsIds);
            if (products.size() != goodsIds.size()) {
                log.error("商品数据异常！");
                throw new ServiceException("商品数据异常，请刷新页面重新下单！");
            }

            List<SlkjShopProduct> shopProducts = slkjShopProductMapper.selectShopProductListByProductIds(goodsIds);
            if (CollectionUtils.isEmpty(shopProducts)) {
                log.error("当前门店没有关联商品！");
                throw new ServiceException("当前门店没有关联商品，请刷新页面重新下单！");
            }

            List<Long> shopGoodsIds = shopProducts.stream()
                    .filter(sp -> ("0".equals(sp.getProductStatus()) && "0".equals(sp.getDelFlag())))
                    .map(SlkjShopProduct::getProductId)
                    .collect(Collectors.toList());
            if (shopGoodsIds.size() != goodsIds.size()) {
                log.error("当前门店没有关联商品！");
                throw new ServiceException("当前门店没有关联商品，请刷新页面重新下单！");
            }

            long count = products.stream().filter(i -> "1".equals(i.getStatus()) || "1".equals(i.getDelFlag())).count();
            if (count > 0) {
                log.error("商品被下架/删除！");
                throw new ServiceException("商品被下架/删除，请刷新页面重新下单！");
            }
            log.info("商品参数，验证通过！");
        }
        log.info("参数无误，全部验证通过！！！");
    }

    @Override
    protected SlkjOrder createOrder(PaymentRequest request, String createBy, OrderSource source) {
        SlkjOrder order = new SlkjOrder();
        SlkjShop shop = slkjShopMapper.selectSlkjShopByShopId(request.getShopId());
        order.setShopId(shop.getShopId());
        order.setShopName(shop.getShopName());
        order.setSource(source.getCode());
        order.setProjectId(request.getProjectId());
        Project project = projectMapper.selectProjectByProjectId(request.getProjectId());
        order.setProjectName(project.getName());
        if (source.equals(OrderSource.SHOP)) {
            order.setVerifyCode("无");
        } else if (source.equals(OrderSource.DOUYIN)) {
//            抖音核销码拿不到
            order.setVerifyCode("无");
        } else {
            order.setVerifyCode(NumberGenerator.getCharacters(7));
        }
        order.setCreateBy(createBy);
        order.setCreateTime(DateUtils.getNowDate());
        order.setOrderNumber(generateOrderNumber(order.getShopId(), order.getSource(), order.getCreateTime()));

        Set<String> keys = request.getPayInventories()
                .stream()
                .map(PaymentRequest.PayInventory::getType)
                .collect(Collectors.toSet());
        if (keys.size() == 2) {
            order.setOrderType(OrderType.OT_103.getCode());
        } else if (keys.contains(PaymentRequest.TICKET)) {
            order.setOrderType(OrderType.OT_101.getCode());
        } else {
            order.setOrderType(OrderType.OT_102.getCode());
        }
        return order;
    }

    @Override
    protected int calculateTotalPrice(List<PaymentRequest.PayInventory> items, OrderSource source) {
        int totalAmount = 0;
        Map<String, List<PaymentRequest.PayInventory>> listMap = items.stream().collect(Collectors.groupingBy(PaymentRequest.PayInventory::getType));

        if (listMap.containsKey(PaymentRequest.TICKET)) {
            List<PaymentRequest.PayInventory> tickets = listMap.get(PaymentRequest.TICKET);
            List<Long> fareSchemeDetailIds = tickets.stream().map(PaymentRequest.PayInventory::getItemId).collect(Collectors.toList());
            Map<Long, SlkjFareSchemeDetail> schemeDetailMap = slkjFareSchemeDetailMapper.selectSlkjFareSchemeDetailByIds(fareSchemeDetailIds)
                    .stream()
                    .collect(Collectors.toMap(SlkjFareSchemeDetail::getId, Function.identity()));
            totalAmount = tickets.stream().mapToInt(i -> {
                SlkjFareSchemeDetail detail = schemeDetailMap.get(i.getItemId());
                if (Objects.nonNull(detail)) {
                    if (source.equals(OrderSource.SHOP)) {
                        int shopPrice = Integer.parseInt(detail.getShopPrice());
                        return shopPrice * i.getQuantity();
                    } else if (source.equals(OrderSource.MINI_PROGRAM)) {
                        int miniAppPrice = Integer.parseInt(detail.getMiniProgramPrice());
                        return miniAppPrice * i.getQuantity();
                    } else if (source.equals(OrderSource.DOUYIN)) {
                        int douyinPrice = Integer.parseInt(detail.getDouyinPrice());
                        return douyinPrice * i.getQuantity();
                    }
                }
                return 0;
            }).sum();

            log.info("当前订单，门票总价：{}", totalAmount);
        }

        if (listMap.containsKey(PaymentRequest.GOODS)) {
            List<PaymentRequest.PayInventory> goods = listMap.get(PaymentRequest.GOODS);
            List<Long> goodsIds = goods.stream()
                    .map(PaymentRequest.PayInventory::getItemId)
                    .collect(Collectors.toList());

            Map<Long, SlkjProduct> productMap = slkjProductMapper.selectProductByProductIds(goodsIds)
                    .stream()
                    .collect(Collectors.toMap(SlkjProduct::getProductId, Function.identity()));
            int goodsAmount = goods.stream().mapToInt(i -> {
                SlkjProduct product = productMap.get(i.getItemId());
                if (Objects.nonNull(product)) {
                    return Math.toIntExact(product.getPrice() * i.getQuantity());
                }
                return 0;
            }).sum();

            log.info("当前订单，商品总价：{}", goodsAmount);
            totalAmount += goodsAmount;
        }

        log.info("当前订单总价：{}", totalAmount);
        return Math.max(totalAmount, 0);
    }

    @Override
    protected SlkjOrder initOrderStatus(SlkjOrder order, String paymentMethod) {
        if (paymentMethod.equals(PaymentRequest.CASH_PAY)) {
            log.info("当前订单 [{}] 用户选择现金支付，无需调用第三方支付接口！", order.getOrderNumber());
            order.setPaymentStatus(LakalaTradeStateEnum.SUCCESS.name());
            order.setPaymentType(LakalaPaymentTypeEnum.INCASH.name());
            order.setPaymentTime(order.getCreateTime());
            switch (OrderType.fromCode(order.getOrderType())) {
                case OT_101:
                    if (order.getSource() == OrderSource.DOUYIN.getCode()) {
                        order.setBusinessStatus(OrderBusinessStatus.UNREDEEMED.getCode());
                    } else {
                        order.setBusinessStatus(OrderBusinessStatus.REDEEMED.getCode());
                    }
                    break;
                case OT_102:
                    order.setGoodsStatus(GoodsStatusEnum.COMPLETED.name());
                    break;
                case OT_103:
                    order.setBusinessStatus(OrderBusinessStatus.REDEEMED.getCode());
                    order.setGoodsStatus(GoodsStatusEnum.COMPLETED.name());
                    break;
            }
            return order;
        }

        if (order.getActualAmount() > 0) {
            log.info("当前订单 [{}] 用户最终需支付：{}分！！！", order.getOrderNumber(), order.getActualAmount());
            order.setPaymentStatus(LakalaTradeStateEnum.INIT.name());
            switch (OrderType.fromCode(order.getOrderType())) {
                case OT_101:
                    order.setBusinessStatus(OrderBusinessStatus.PENDING_PAYMENT.getCode());
                    break;
                case OT_102:
                    order.setGoodsStatus(GoodsStatusEnum.PENDING_PAYMENT.name());
                    break;
                case OT_103:
                    order.setBusinessStatus(OrderBusinessStatus.PENDING_PAYMENT.getCode());
                    order.setGoodsStatus(GoodsStatusEnum.PENDING_PAYMENT.name());
                    break;
            }
        } else {
            log.info("当前订单 [{}] 属于0元购，无需调用第三方扣款！", order.getOrderNumber());
            order.setPaymentStatus(LakalaTradeStateEnum.SUCCESS.name());
            order.setPaymentTime(order.getCreateTime());
            switch (OrderType.fromCode(order.getOrderType())) {
                case OT_101:
                    if (order.getSource() == OrderSource.SHOP.getCode()) {
                        order.setBusinessStatus(OrderBusinessStatus.REDEEMED.getCode());
                    } else {
                        order.setBusinessStatus(OrderBusinessStatus.UNREDEEMED.getCode());
                    }
                    break;
                case OT_102:
                    if (order.getSource() == OrderSource.SHOP.getCode()) {
                        order.setGoodsStatus(GoodsStatusEnum.COMPLETED.name());
                    } else {
                        order.setGoodsStatus(GoodsStatusEnum.WAITING_FOR_PICKUP.name());
                    }
                    break;
                case OT_103:// 小程序目前不支持混合订单
                    order.setBusinessStatus(OrderBusinessStatus.REDEEMED.getCode());
                    order.setGoodsStatus(GoodsStatusEnum.COMPLETED.name());
                    break;
            }
        }
        return order;
    }

    @Override
    protected Long saveOrder(SlkjOrder order, List<PaymentRequest.PayInventory> items, String paymentMethod) {
        if (paymentMethod.equals(PaymentRequest.ONLINE_PAY)) {
            // 设置支付请求ID
            order.setPaymentRequestId(NumberGenerator.getCharacters(23));
        }
        log.info("生成订单：{}", JSON.toJSONString(order));
        slkjOrderMapper.insertSlkjOrder(order);

        SlkjOrderStatusLog statusLog = new SlkjOrderStatusLog();
        statusLog.setOrderId(order.getOrderId());
        if (order.getOrderType() == OrderType.OT_102.getCode()) {
            statusLog.setStatus(order.getGoodsStatus());
        } else {
            statusLog.setStatus(order.getBusinessStatus());
        }
        statusLog.setChangeBy(Long.parseLong(order.getCreateBy()));
        statusLog.setChangeTime(order.getCreateTime());
        log.info("生成订单状态日志：{}", JSON.toJSONString(statusLog));
        slkjOrderStatusLogMapper.insert(statusLog);

        log.info("构建订单对应票价方案/商品快照...");
        List<SlkjOrderPricingSnapshot> snapshots = new ArrayList<>();
        Map<String, List<Long>> collect = items.stream()
                .collect(Collectors.groupingBy(
                        PaymentRequest.PayInventory::getType,
                        Collectors.mapping(PaymentRequest.PayInventory::getItemId, Collectors.toList())
                ));
        // 门票
        List<Long> fareSchemeDetailIds = collect.get(PaymentRequest.TICKET);
        if (CollectionUtils.isNotEmpty(fareSchemeDetailIds)) {
            List<Long> categoryIds = new ArrayList<>();
            List<Long> levelIds = new ArrayList<>();
            List<SlkjFareSchemeDetail> schemeDetails = slkjFareSchemeDetailMapper.selectSlkjFareSchemeDetailByIds(fareSchemeDetailIds);
            for (SlkjFareSchemeDetail detail : schemeDetails) {
                categoryIds.add(detail.getTicketCategoryId());
                levelIds.add(detail.getTicketLevelId());
            }
            Map<Long, SlkjFareSchemeDetail> schemeDetailMap = schemeDetails.stream()
                    .collect(Collectors.toMap(SlkjFareSchemeDetail::getId, Function.identity()));

            Long fareSchemeId = schemeDetails.get(0).getFareSchemeId();
            SlkjFareScheme fareScheme = slkjFareSchemeMapper.selectSlkjFareSchemeById(fareSchemeId);

            Map<Long, SlkjTicketCategory> categoryMap = slkjTicketCategoryMapper.selectSlkjTicketCategoryByIds(categoryIds)
                    .stream()
                    .collect(Collectors.toMap(SlkjTicketCategory::getId, Function.identity()));

            Map<Long, SlkjTicketLevel> levelMap = slkjTicketLevelMapper.selectSlkjTicketLevelListByIds(levelIds)
                    .stream()
                    .collect(Collectors.toMap(SlkjTicketLevel::getId, Function.identity()));

            items.stream()
                    .filter(i -> i.getType().equals(PaymentRequest.TICKET))
                    .forEach(i -> {
                        SlkjOrderPricingSnapshot snapshot = new SlkjOrderPricingSnapshot();
                        snapshot.setOrderId(order.getOrderId());
                        snapshot.setFareSchemeId(fareSchemeId);
                        snapshot.setFareSchemeName(fareScheme.getSchemeName());

                        SlkjFareSchemeDetail detail = schemeDetailMap.get(i.getItemId());
                        snapshot.setFareSchemeDetailId(detail.getId());
                        snapshot.setShopPrice(detail.getShopPrice());
                        snapshot.setMiniProgramPrice(detail.getMiniProgramPrice());
                        snapshot.setDouyinPrice(detail.getDouyinPrice());
                        snapshot.setOriginalPrice(detail.getOriginalPrice());

                        SlkjTicketLevel ticketLevel = levelMap.get(detail.getTicketLevelId());
                        snapshot.setTicketLevelId(ticketLevel.getId());
                        snapshot.setTicketLevelName(ticketLevel.getName());

                        SlkjTicketCategory ticketCategory = categoryMap.get(detail.getTicketCategoryId());
                        snapshot.setTicketCategoryId(ticketCategory.getId());
                        snapshot.setTicketCategoryName(ticketCategory.getName());
                        snapshot.setQuantity(ticketCategory.getQuantity());

                        snapshot.setItemType(PaymentRequest.TICKET);
                        snapshot.setBayQuantity(i.getQuantity());

                        if (order.getSource() == OrderSource.SHOP.getCode()) {
                            int amount = Integer.parseInt(detail.getShopPrice()) * i.getQuantity();
                            snapshot.setUserActualAmount(amount);
                        } else if (order.getSource() == OrderSource.MINI_PROGRAM.getCode()) {
                            int amount = Integer.parseInt(detail.getMiniProgramPrice()) * i.getQuantity();
                            snapshot.setUserActualAmount(amount);
                        } else if (order.getSource() == OrderSource.DOUYIN.getCode()) {
                            int amount = Integer.parseInt(detail.getDouyinPrice()) * i.getQuantity();
                            snapshot.setUserActualAmount(amount);
                        }

                        snapshots.add(snapshot);
                    });
        }

        // 商品
        List<Long> goodsIds = collect.get(PaymentRequest.GOODS);
        if (CollectionUtils.isNotEmpty(goodsIds)) {
            Map<Long, SlkjProduct> productMap = slkjProductMapper.selectProductByProductIds(goodsIds)
                    .stream()
                    .collect(Collectors.toMap(SlkjProduct::getProductId, Function.identity()));
            items.stream()
                    .filter(i -> i.getType().equals(PaymentRequest.GOODS))
                    .forEach(i -> {
                        SlkjOrderPricingSnapshot snapshot = new SlkjOrderPricingSnapshot();
                        snapshot.setOrderId(order.getOrderId());
                        snapshot.setQuantity(1);
                        snapshot.setItemType(PaymentRequest.GOODS);

                        SlkjProduct product = productMap.get(i.getItemId());
                        snapshot.setGoodsId(product.getProductId());
                        snapshot.setGoodsName(product.getName());
                        int price = Math.toIntExact(product.getPrice());
                        snapshot.setGoodsPrice(price);
                        snapshot.setGoodsCostPrice(product.getPrincipal());
                        snapshot.setUserActualAmount(price * i.getQuantity());
                        snapshot.setBayQuantity(i.getQuantity());
                        snapshots.add(snapshot);
                    });
        }
        log.info("构建订单对应票价方案/商品快照完成！:{}", JSON.toJSONString(snapshots));

        log.info("批量插入，票类/商品快照...");
        int insert = slkjOrderPricingSnapshotMapper.batchInsert(snapshots);
        if (insert != snapshots.size()) {
            log.error("订单快照插入失败！");
            throw new RuntimeException("订单快照插入失败，请刷新重试！");
        }

        // 分账
        log.info("构建订单分账相关快照...");
        List<SlkjOrderSplitSnapshot> splitSnapshots = new ArrayList<>();
        // 票务系统
        SharesPosVo posVo = slkjShopPosMapper.selectPosShopByShopId(order.getShopId());
        SlkjOrderSplitSnapshot snapshot = new SlkjOrderSplitSnapshot();
        snapshot.setOrderId(order.getOrderId());
        snapshot.setRelatedId(posVo.getId());
        snapshot.setRelatedType(SlkjOrderSplitSnapshot.TICKET_SYSTEM);
        snapshot.setPreRecRatio(BigDecimal.ZERO);
        snapshot.setPostRecRatio(BigDecimal.ZERO);
        snapshot.setSplitRatio(BigDecimal.valueOf(posVo.getShares()));
        snapshot.setOtherFields(JSON.toJSONString(posVo));
        splitSnapshots.add(snapshot);

        // 投资方
        List<SharesInvestorVo> investorVos = slkjShopInvestorMapper.selectInvestorShopByShopId(order.getShopId());
        if (CollectionUtils.isNotEmpty(investorVos)) {
            for (SharesInvestorVo vo : investorVos) {
                snapshot = new SlkjOrderSplitSnapshot();
                snapshot.setOrderId(order.getOrderId());
                snapshot.setRelatedId(vo.getId());
                snapshot.setRelatedType(SlkjOrderSplitSnapshot.INVESTOR);
                snapshot.setPreRecRatio(BigDecimal.valueOf(vo.getInvestorBefore()));
                snapshot.setPostRecRatio(BigDecimal.valueOf(vo.getInvestorAfter()));
                snapshot.setSplitRatio(BigDecimal.ZERO);
                snapshot.setOtherFields(JSON.toJSONString(vo));
                splitSnapshots.add(snapshot);
            }
        }

        //  项目
        SlkjShopProject currentShopProject = slkjShopProjectMapper.selectCurrentShowingProjectByShopId(order.getShopId());
        snapshot = new SlkjOrderSplitSnapshot();
        snapshot.setOrderId(order.getOrderId());
        snapshot.setRelatedId(currentShopProject.getId());
        snapshot.setRelatedType(SlkjOrderSplitSnapshot.PROJECT);
        snapshot.setPreRecRatio(BigDecimal.ZERO);
        snapshot.setPostRecRatio(BigDecimal.ZERO);
        snapshot.setSplitRatio(BigDecimal.valueOf(currentShopProject.getShares()));
        snapshot.setOtherFields(JSON.toJSONString(currentShopProject));
        splitSnapshots.add(snapshot);

        // 运营
        ShopOperateVo shopOperateVo = slkjShopOperateMapper.selectOperateShopByShopId(order.getShopId());
        snapshot = new SlkjOrderSplitSnapshot();
        snapshot.setOrderId(order.getOrderId());
        snapshot.setRelatedId(shopOperateVo.getId());
        snapshot.setRelatedType(SlkjOrderSplitSnapshot.OPERATION);
        snapshot.setPreRecRatio(BigDecimal.valueOf(shopOperateVo.getInvestorBefore()));
        snapshot.setPostRecRatio(BigDecimal.valueOf(shopOperateVo.getInvestorAfter()));
        snapshot.setSplitRatio(BigDecimal.ZERO);
        snapshot.setOtherFields(JSON.toJSONString(shopOperateVo));
        splitSnapshots.add(snapshot);
        log.info("构建订单对应分账快照完成！:{}", JSON.toJSONString(splitSnapshots));

        log.info("批量插入，分账快照...");
        int count = slkjOrderSplitSnapshotMapper.batchInsert(splitSnapshots);
        if (count != splitSnapshots.size()) {
            log.error("订单分账插入失败！");
            throw new RuntimeException("订单分账插入失败，请刷新重试！");
        }

        // 如果是微信小程序订单，未支付之前构建支付订单快照
        if (OrderSource.MINI_PROGRAM.getCode() == order.getSource()) {
            applicationEventPublisher.publishEvent(ActionEvent.of(order, "构建微信小程序订单快照信息！"));
        }
        return order.getOrderId();
    }

    @Override
    protected void processPayment(SlkjOrder order, String authCode, String paymentMethod) {
        log.info("异步计算投资人分账金额");
        applicationEventPublisher.publishEvent(ActionEvent.of(order, "计算分账金额"));

        if (paymentMethod.equals(PaymentRequest.CASH_PAY)) {
            log.info("用户现金支付，订单逻辑至此已结束！！！");
            return;
        }

        if (paymentMethod.equals(PaymentRequest.ONLINE_PAY)) {
            log.info("用户在线支付！");
            log.info("构建支付请求参数...");
            LakalaMicroPayRequest microPayRequest = new LakalaMicroPayRequest();
            String decode = new String(Base64.getDecoder().decode(authCode));
            microPayRequest.setAuthCode(decode);
            microPayRequest.setOutTradeNo(order.getPaymentRequestId());
            microPayRequest.setSubject(order.getProjectName());
            microPayRequest.setRemark("用户门店购买！");
            microPayRequest.setShopId(order.getShopId());

            microPayRequest.setTotalAmount(order.getActualAmount() + "");
            String activeProfile = env.getProperty("spring.profiles.active");
            if ("dev".equals(activeProfile) || "test".equals(activeProfile)) {
                log.info("当前运行环境 [{}]，调用拉卡拉支付金额设置为 1 分钱！", activeProfile);
                microPayRequest.setTotalAmount("1");
            }

            log.info("调用拉卡拉支付接口：{}", JSON.toJSONString(microPayRequest));
            LakalaMicroPayResponse response;
            try {
                response = lakalaMicroPayService.microPay(microPayRequest);
                log.info("[payment_request_id={}] 对应支付响应：{}", order.getPaymentRequestId(), JSON.toJSONString(response));
                if (Objects.isNull(response) || Objects.isNull(response.getRespData())) {
                    log.error("支付异常！！！");
                    throw new RuntimeException("支付异常，请刷新重试！");
                }
            } catch (LakalaException e) {
                log.error("支付参数异常！！！", e);
                dingTalkService.sendTextMessage("拉卡拉支付异常：" + e.getMessage() + "，对应入参：" + JSON.toJSONString(microPayRequest), true);
                throw new RuntimeException("支付异常，请检查参数！");
            }
            log.info("拉卡拉支付数据入库...");
            SlkjOrderLakal orderLakal = new SlkjOrderLakal();
            BeanUtils.copyProperties(response.getRespData(), orderLakal);
            orderLakal.setOrderId(order.getOrderId());
            orderLakal.setCreateTime(DateUtils.getNowDate());
            orderLakal.setAccRespFields(JSON.toJSONString(response));
            slkjOrderLakalMapper.insert(orderLakal);

            LakalaResponseCodeEnum lrce = LakalaResponseCodeEnum.fromCode(response.getCode());
            if (Arrays.asList(LakalaResponseCodeEnum.BBS00000, LakalaResponseCodeEnum.BBS11112, LakalaResponseCodeEnum.BBS11105, LakalaResponseCodeEnum.BBS10000).contains(lrce)) {
                SlkjOrder slkjOrder = new SlkjOrder();
                slkjOrder.setOrderId(order.getOrderId());
                slkjOrder.setPaymentType(response.getRespData().getAccountType());
                // 实付金额
                if (StringUtils.isNotEmpty(response.getRespData().getAccSettleAmount())) {
                    String amount = response.getRespData().getAccSettleAmount().replaceAll("^\"|\"$", "");
                    slkjOrder.setActualAmount(Integer.parseInt(amount));
                }

                log.info("将订单 [{}] 业务状态及支付状态，更新为：支付中...", order.getOrderNumber());
                slkjOrder.setPaymentStatus(LakalaTradeStateEnum.CREATE.name());
                slkjOrder.setThirdOrderNumber(response.getRespData().getLogNo());
                slkjOrder.setUpdateTime(DateUtils.getNowDate());
                slkjOrderMapper.updateSlkjOrder(slkjOrder);

                log.info("轮询订单 [{}] 支付状态...", order.getOrderNumber());
                // 重试机制
                // 最多执行 5 次，总等待时间约为 7.5 秒（不包括初始调用时间和每次调用的执行时间）。
                // 500 + 1000 + 2000 + 2000 + 2000 + 2000 = 7500毫秒
                Retryer<Boolean> retryer = RetryerBuilder.<Boolean>newBuilder()
                        .retryIfException()
                        .retryIfResult(Boolean.FALSE::equals)
                        .withWaitStrategy(WaitStrategies.exponentialWait(500, 2, TimeUnit.SECONDS))
                        .withStopStrategy(StopStrategies.stopAfterAttempt(5))
                        .build();

                // 存储最后一次成功执行的 TradeQueryResponse 对象
                AtomicReference<TradeQueryResponse> lastSuccessfulTradeQuery = new AtomicReference<>();
                // 存储最后一次尝试的结果状态
                final String[] lastTradeState = {null};

                Callable<Boolean> callable = () -> {
                    TradeQueryResponse tradeQuery = lakalaMicroPayService.tradeQuery(order.getPaymentRequestId(), order.getShopId());
                    lastTradeState[0] = tradeQuery.getRespData().getTradeState();
                    if (LakalaTradeStateEnum.fromState(lastTradeState[0]).equals(LakalaTradeStateEnum.SUCCESS)) {
                        lastSuccessfulTradeQuery.set(tradeQuery);
                        return true;
                    }
                    return false;
                };

                try {
                    // 执行重试机制
                    boolean paymentSuccess = retryer.call(callable);
                    if (paymentSuccess) {
                        log.info("订单 [{}] 支付成功！！！", order.getOrderNumber());
                        TradeQueryResponse queryResponse = lastSuccessfulTradeQuery.get();
                        if (Objects.nonNull(queryResponse)) {
                            String accSettleAmount = queryResponse.getRespData().getAccSettleAmount();
                            if (StringUtils.isNotEmpty(accSettleAmount)) {
                                accSettleAmount = accSettleAmount.replaceAll("^\"|\"$", "");
                                slkjOrder.setActualAmount(Integer.parseInt(accSettleAmount));
                            }

                            switch (OrderType.fromCode(order.getOrderType())) {
                                case OT_101:
                                    if (order.getSource() == OrderSource.SHOP.getCode()) {
                                        slkjOrder.setBusinessStatus(OrderBusinessStatus.REDEEMED.getCode());
                                    } else {
                                        slkjOrder.setBusinessStatus(OrderBusinessStatus.UNREDEEMED.getCode());
                                    }
                                    break;
                                case OT_102:
                                    if (order.getSource() == OrderSource.SHOP.getCode()) {
                                        slkjOrder.setGoodsStatus(GoodsStatusEnum.COMPLETED.name());
                                    } else {
                                        if (StringUtils.isNotBlank(order.getAddressSnapshot())) {
                                            slkjOrder.setGoodsStatus(GoodsStatusEnum.WAITING_FOR_SHIPPING.name());
                                        } else {
                                            slkjOrder.setGoodsStatus(GoodsStatusEnum.WAITING_FOR_PICKUP.name());
                                        }
                                    }
                                    break;
                                case OT_103:// 小程序目前不支持混合订单
                                    slkjOrder.setBusinessStatus(OrderBusinessStatus.REDEEMED.getCode());
                                    slkjOrder.setGoodsStatus(GoodsStatusEnum.COMPLETED.name());
                                    break;
                            }

                            slkjOrder.setPaymentStatus(LakalaTradeStateEnum.SUCCESS.name());
                            slkjOrder.setThirdOrderNumber(response.getRespData().getLogNo());
                            slkjOrder.setPaymentTime(DateUtils.dateTime(DateUtils.YYYYMMDDHHMMSS, response.getRespData().getTradeTime()));
                            slkjOrder.setUpdateTime(DateUtils.getNowDate());
                            slkjOrder.setUpdateBy(order.getCreateBy());
                            slkjOrder.setAccTradeNo(response.getRespData().getAccTradeNo());

                            log.info("将订单支付状态改为，支付成功：{}", JSON.toJSONString(slkjOrder));
                            slkjOrderMapper.updateSlkjOrder(slkjOrder);

                            log.info("构建订单业务状态变更记录...");
                            SlkjOrderStatusLog statusLog = new SlkjOrderStatusLog();
                            statusLog.setOrderId(order.getOrderId());
                            statusLog.setStatus(OrderBusinessStatus.REDEEMED.getCode());
                            statusLog.setChangeBy(Long.valueOf(order.getCreateBy()));
                            statusLog.setChangeTime(DateUtils.getNowDate());
                            log.info("插入订单业务状态变更记录！:{}", JSON.toJSONString(statusLog));
                            slkjOrderStatusLogMapper.insert(statusLog);
                        } else {
                            log.error("拉卡拉支付查询结果为空，数据二次补偿！");
                            statusCompensation(order, new String[]{LakalaTradeStateEnum.DEAL.name()});
                        }
                    } else {
                        // 支付未成功，插入补偿数据
                        statusCompensation(order, lastTradeState);
                        throw new ServiceException("支付中，请刷新订单！", HttpStatus.BE_PAYING);
                    }
                } catch (ExecutionException | RetryException | NumberFormatException e) {
                    // 捕获异常，插入补偿数据
                    statusCompensation(order, lastTradeState);
                    log.error("支付查询出现异常！", e);
                    throw new ServiceException("支付中，请刷新订单！", HttpStatus.BE_PAYING);
                }
            } else {
                log.error("订单 [{}] 支付异常，拉卡拉响应：{}", order.getOrderNumber(), response.getCode() + ":" + response.getMsg());
                throw new ServiceException(response.getMsg());
            }
            return;
        }
        throw new RuntimeException("支付方式有误，请检查！");
    }

    @Override
    protected void validateRequest(long orderId, String paymentMethod) {
        SlkjOrder order = slkjOrderMapper.selectSlkjOrderByOrderId(orderId);
        if (Objects.isNull(order)) {
            throw new ServiceException("订单不存在！");
        }

        if (LakalaTradeStateEnum.SUCCESS.name().equals(order.getPaymentStatus())) {
            throw new ServiceException("订单已支付，请勿重复支付！");
        }

        if (paymentMethod.equals(LakalaPaymentTypeEnum.INCASH.getCode())) {
            throw new ServiceException("现金支付订单，暂不支持重新付款！");
        }

        if (LakalaTradeStateEnum.REFUND.name().equals(order.getPaymentStatus())) {
            throw new ServiceException("订单已退款，禁止再次付款！");
        }

        // 只有 FAIL、CLOSE 状态才允许支付，但是如果业务支持部分退款，那么就需要调整
        if (!Arrays.asList(LakalaTradeStateEnum.CLOSE.name(), LakalaTradeStateEnum.FAIL.name()).contains(order.getPaymentStatus())) {
            throw new ServiceException("正在支付，请稍等！");
        }

        if (order.getPaymentType() != null && order.getPaymentType().equals(LakalaPaymentTypeEnum.INCASH.getCode())) {
            throw new ServiceException("现金支付订单，禁止重新付款！");
        }

        if (order.getBusinessStatus().equals(OrderBusinessStatus.ORDER_CANCELLED.getCode())) {
            throw new ServiceException("订单已过期，禁止付款！");
        }

        Project project = projectMapper.selectProjectByProjectId(order.getProjectId());
        if (Objects.isNull(project)) {
            throw new ServiceException("项目不存在！");
        }

        SlkjShopProject shopProject = slkjShopProjectMapper.selectCurrentShowingProjectByShopId(order.getShopId());
        if (Objects.isNull(shopProject)) {
            throw new ServiceException("门店暂无上映项目，禁止下单！");
        }

        if (Objects.isNull(shopProject.getProjectId()) || !shopProject.getProjectId().equals(order.getProjectId())) {
            throw new ServiceException("当前项目已下架，禁止下单！");
        }

        SlkjShop shop = slkjShopMapper.selectSlkjShopByShopId(order.getShopId());
        if (Objects.isNull(shop)) {
            throw new ServiceException("门店不存在！");
        }

        if ("1".equals(shop.getStatus())) {
            throw new ServiceException("门店状态异常，禁止下单！");
        }

        if ("1".equals(shop.getDelFlag())) {
            throw new ServiceException("门店状态异常，禁止下单！");
        }
    }

    @Override
    protected SlkjOrder resetPaymentRequestId(long orderId, String updateBy) {
        SlkjOrder order = slkjOrderMapper.selectSlkjOrderByOrderId(orderId);
        log.info("订单 [{}] 重置支付请求ID...", order.getOrderNumber());
        log.info("当前支付请求 ID：{}", order.getPaymentRequestId());

        String newRequestId = NumberGenerator.getCharacters(23);
        order.setPaymentRequestId(newRequestId);
        log.info("最新支付请求 ID：{}", newRequestId);

        if (order.getActualAmount() > 0) {
            log.info("当前订单 [{}] 用户最终需支付：{}分！！！", order.getOrderNumber(), order.getActualAmount());
            order.setPaymentStatus(LakalaTradeStateEnum.INIT.name());
            switch (OrderType.fromCode(order.getOrderType())) {
                case OT_101:
                    order.setBusinessStatus(OrderBusinessStatus.PENDING_PAYMENT.getCode());
                    break;
                case OT_102:
                    order.setGoodsStatus(GoodsStatusEnum.PENDING_PAYMENT.name());
                    break;
                case OT_103:
                    order.setBusinessStatus(OrderBusinessStatus.PENDING_PAYMENT.getCode());
                    order.setGoodsStatus(GoodsStatusEnum.PENDING_PAYMENT.name());
                    break;
            }
        } else {
            log.info("当前订单 [{}] 属于0元购，无需调用第三方扣款！", order.getOrderNumber());
            order.setBusinessStatus(OrderBusinessStatus.REDEEMED.getCode());
            order.setPaymentStatus(LakalaTradeStateEnum.SUCCESS.name());
            order.setPaymentTime(order.getCreateTime());
            switch (OrderType.fromCode(order.getOrderType())) {
                case OT_101:
                    if (order.getSource() == OrderSource.SHOP.getCode()) {
                        order.setBusinessStatus(OrderBusinessStatus.REDEEMED.getCode());
                    } else {
                        order.setBusinessStatus(OrderBusinessStatus.UNREDEEMED.getCode());
                    }
                    break;
                case OT_102:
                    if (order.getSource() == OrderSource.SHOP.getCode()) {
                        order.setGoodsStatus(GoodsStatusEnum.COMPLETED.name());
                    } else {
                        order.setGoodsStatus(GoodsStatusEnum.WAITING_FOR_PICKUP.name());
                    }
                    break;
                case OT_103: // 小程序目前不支持混合订单
                    order.setBusinessStatus(OrderBusinessStatus.REDEEMED.getCode());
                    order.setGoodsStatus(GoodsStatusEnum.COMPLETED.name());
                    break;
            }
        }

        log.info("更新 slkj_order 订单支付请求ID...");
        order.setUpdateBy(updateBy);
        order.setUpdateTime(DateUtils.getNowDate());
        slkjOrderMapper.updateOrderPaymentRequestId(order);

        log.info("删除 slkj_order_status_compensation 订单补偿信息");
        slkjOrderStatusCompensationMapper.deleteByOrderId(order.getOrderId());

        return order;
    }

    @Override
    protected void handleException(Exception e, String description, String params) {
        dingTalkService.sendTextMessage(description + "：" + e.getMessage() + "，参数信息：" + params, true);
    }

    @Override
    protected ReceiptInfoVo getReceiptInfo(long orderId) {
        return iSlkjOrderService.getReceiptInfo(orderId);
    }

    @Override
    protected SlkjOrder validateRequest(PrepaymentRequest request) {
        SlkjOrder order = slkjOrderMapper.selectSlkjOrderByOrderId(request.getOrderId());
        if (Objects.isNull(order)) {
            throw new ServiceException("订单不存在！");
        }

        if (LakalaTradeStateEnum.SUCCESS.name().equals(order.getPaymentStatus())) {
            throw new ServiceException("订单已支付，禁止重复支付！");
        }

        if (LakalaTradeStateEnum.REFUND.name().equals(order.getPaymentStatus())) {
            throw new ServiceException("订单已退款，禁止再次支付！");
        }

        // 支付状态：INIT-初始化 CREATE-下单成功 SUCCESS-交易成功 FAIL-交易失败 DEAL-交易处理中 UNKNOWN-未知状态 CLOSE-订单关闭 PART_REFUND-部分退款 REFUND-全部退款(或订单被撤销）
        // 只有 FAIL、CLOSE 状态才允许支付，但是如果业务支持部分退款，那么就需要调整
        if (!Arrays.asList(LakalaTradeStateEnum.INIT.name(), LakalaTradeStateEnum.UNKNOWN.name(), LakalaTradeStateEnum.CLOSE.name(), LakalaTradeStateEnum.FAIL.name()).contains(order.getPaymentStatus())) {
            throw new ServiceException("正在支付，请稍等！");
        }

        if (order.getPaymentType() != null && order.getPaymentType().equals(LakalaPaymentTypeEnum.INCASH.getCode())) {
            throw new ServiceException("现金支付订单，禁止重新付款！");
        }

        if (StringUtils.isNotBlank(order.getBusinessStatus()) && order.getBusinessStatus().equals(OrderBusinessStatus.ORDER_CANCELLED.getCode())) {
            throw new ServiceException("订单已过期，禁止付款！");
        }

        if (StringUtils.isNotBlank(order.getGoodsStatus()) && order.getGoodsStatus().equals(OrderBusinessStatus.ORDER_CANCELLED.getCode())) {
            throw new ServiceException("订单已过期，禁止付款！");
        }

        SlkjCustomer customer = slkjCustomerMapper.getCustomerByOpenId(request.getOpenId());
        if (Objects.isNull(customer)) {
            throw new ServiceException("用户不存在，禁止下单！");
        }

        if (order.getCustomerId() == null || !customer.getCustomerId().equals(order.getCustomerId())) {
            throw new ServiceException("用户信息不一致，禁止下单！");
        }

        // 如果是商品订单，需要校验取货方式
        if (order.getOrderType() == OrderType.OT_102.getCode()) {
            if (StringUtils.isBlank(request.getPickupMethod())) {
                throw new ServiceException("请选择取货方式！");
            }

            if (!Arrays.asList("IN_STORE_PICKUP", "DELIVERY_TO_HOME").contains(request.getPickupMethod())) {
                throw new ServiceException("无效的取货方式！");
            }

            if ("DELIVERY_TO_HOME".equals(request.getPickupMethod())) {
                if (!NumberUtil.isLong(request.getAddressId())) {
                    throw new ServiceException("无效的地址ID！");
                }

                if (Objects.isNull(slkjCustomerAddressMapper.selectById(Long.parseLong(request.getAddressId())))) {
                    throw new ServiceException("无效的地址信息！");
                }
            }
        }
        return order;
    }

    @Override
    protected JSONObject processWxPayment(SlkjOrder order, String pickupMethod, String addressId) {
        log.info("开始构建微信预支付信息...");
        log.info("订单号：{}, 会员ID：{}, 支付ID：{}", order.getOrderNumber(), order.getCustomerId(), order.getPaymentRequestId());

        if (order.getOrderType() == OrderType.OT_102.getCode()) {
            log.info("订单类型为商品，处理收获地址！pickupMethod: {}, addressId: {}", pickupMethod, addressId);
            if ("DELIVERY_TO_HOME".equals(pickupMethod)) {
                SlkjCustomerAddress customerAddress = slkjCustomerAddressMapper.selectById(Long.parseLong(addressId));
                CustomerAddressDTO address = BeanUtil.copyProperties(customerAddress, CustomerAddressDTO.class);
                AreaDTO area = sysAreaMapper.findAreaByDistrictId(address.getCountyCode());
                address.setProvinceName(area.getProvinceName());
                address.setCityName(area.getCityName());
                address.setCountyName(area.getDistrictName());
                order.setAddressSnapshot(JSON.toJSONString(address));
                log.info("订单收获地址信息：{}", order.getAddressSnapshot());
                slkjOrderMapper.updateSlkjOrder(order);
            }
        }

        LakalaPreorderRequest request = new LakalaPreorderRequest();
        request.setPaymentRequestId(order.getPaymentRequestId());
        request.setTotalAmount(order.getActualAmount() + "");
        String activeProfile = env.getProperty("spring.profiles.active");
        if ("dev".equals(activeProfile) || "test".equals(activeProfile)) {
            log.info("当前运行环境 [{}]，小程序支付金额金额设置为 1 分钱！", activeProfile);
            request.setTotalAmount("1");
        }
        request.setSubject(order.getShopName());
        OrderType type = OrderType.fromCode(order.getOrderType());
        request.setRemark(type.getDescription());
        SlkjCustomer customer = slkjCustomerMapper.getCustomerByCustomerId(order.getCustomerId());
        request.setOpenId(customer.getOpenId());
        request.setAppId(weChatProperties.getMiniAppId());
        request.setShopId(order.getShopId());

        log.info("构建微信预支付信息：{}", JSON.toJSONString(request));
        try {
            LakalaPreorderResponse response = lakalaPreorderService.preorder(request);
            log.info("微信预支付响应信息：{}", JSON.toJSONString(response));
            if (Objects.isNull(response) || Objects.isNull(response.getRespData()) || Objects.isNull(response.getRespData().getAccRespFields())) {
                log.error("微信预支付响应信息为空，订单号：{}", order.getOrderNumber());
                throw new RuntimeException("系统异常，请重新下单！");
            }

            log.info("启动异步监听，实时获取订单 [{}] 支付状态！", order.getOrderNumber());
            OrderAction action = new OrderAction();
            BeanUtils.copyProperties(order, action);
            applicationEventPublisher.publishEvent(action);

            return response.getRespData().getAccRespFields();
        } catch (LakalaException e) {
            log.error("微信预支付异常，订单号：{}，异常信息：{}", order.getOrderNumber(), e.getMessage());
            throw new RuntimeException("系统异常，请重新下单！");
        }
    }

    private synchronized String generateOrderNumber(Long shopId, Integer source, Date createTime) {
        log.info("生成订单编号...");
        StringBuilder sb = new StringBuilder();
        // 前缀
        String prefix = Strings.padStart(String.valueOf(shopId), 3, '0');
        sb.append(prefix);

        // 时间
        String time = DateUtils.parseDateToStr(DateUtils.YYYYMMDD, createTime);
        sb.append(time);

        // 渠道
        sb.append(source);

        // 增量流水号
        Long incr;
        String key = INCR_ORDER_NUMBER_PREFIX + time + ":" + shopId;
        if (redisCache.hasKey(key)) {
            incr = redisCache.incr(key);
        } else {
            // 24小时内，重置流水号
            incr = redisCache.incr(key, 24, TimeUnit.HOURS);
        }
        if (Objects.isNull(incr)) {
            // 补偿机制
            // 如果获取不到，则生成随机流水号
            String number = NumberGenerator.getCharacters(5);
            sb.append(number);
        } else {
            sb.append(Strings.padStart(String.valueOf(incr), 5, '0'));
        }
        log.info("订单编号：{}", sb);
        return sb.toString();
    }


    private void statusCompensation(SlkjOrder order, String[] lastTradeState) {
        SlkjOrderStatusCompensation orderStatusCompensation = new SlkjOrderStatusCompensation();
        orderStatusCompensation.setOrderId(order.getOrderId());
        orderStatusCompensation.setOrderNumber(order.getOrderNumber());
        orderStatusCompensation.setPaymentRequestId(order.getPaymentRequestId());
        orderStatusCompensation.setStatus(lastTradeState[0]);
        orderStatusCompensation.setAttempts(0);
        orderStatusCompensation.setCreateTime(DateUtils.getNowDate());
        orderStatusCompensation.setShopId(order.getShopId());
        log.info("订单 [{}] 支付状态未成功，插入补偿数据！", order.getOrderNumber());
        slkjOrderStatusCompensationMapper.insert(orderStatusCompensation);
    }

}
